<!DOCTYPE html>
<!--<html manifest="offline.manifest" lang="ja">-->
<html lang="ja">

<head>
	<meta charset="utf-8" />
	<meta name="robots" content="noindex">
	<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
	<title>ESPレーサー CC</title>
	<meta name="description" content="ESPレーサーのWebAppコマンドコントロール版 Android,Windows,Macに対応 JavaScriptでESPRacerを制御できます" />
	<link rel="icon" href="image/icon16.png" sizes="16x16" type="image/png" />
	<link rel="icon" href="image/icon32.png" sizes="32x32" type="image/png" />
	<link rel="icon" href="image/icon48.png" sizes="48x48" type="image/png" />
	<link rel="icon" href="image/icon64.png" sizes="64x64" type="image/png" />
	<link rel="apple-touch-icon-precomposed" href="image/icon150.png" />
	<meta name="msapplication-TileImage" content="image/icon150.png" />
	<meta name="msapplication-TileColor" content="#ff0000" />
	<link rel="stylesheet" href="data/style.css?ver=2" />
	<script type="text/javascript" src="data/bluejelly.js"></script>
</head>

<body>
	<div id='LoadingLayer'>
		<div id='LoadingImage'>
			<img src="image/Loading.png" id='LoadingImageSource'>
			<div id='LoadingText'></div>
		</div>
	</div>
	<div id='NoSupportLayer'>
		<div class="center" id='NoSupportContent'>
			<div id='SupportList'>
				<table align="center">
					<tr>
						<td colspan="2" class='errorTop'><img src="image/Error.png" id="ErrorImage"></td>
					</tr>
					<tr>
						<td colspan="2" class='errorTop'>ご利用のブラウザには対応しておりません<br>以下のサポートリストをご確認ください</td>
					</tr>
					<tr>
						<th colspan="2">サポートリスト</th>
					</tr>
					<tr class='top' class='underline'>
						<td>OS</td>
						<td>ブラウザ</td>
					</tr>
					<tr class='underline'>
						<td rowspan="2" class='OS'>iOS</td>
						<td><a href='https://apps.apple.com/us/app/bluefy-web-ble-browser/id1492822055'>Bluefy</a></td>
					</tr>
					<tr>
						<td><a href='https://apps.apple.com/us/app/plen/id1561905612'>公式アプリ</a></td>
					</tr>
					<tr class='underline'>
						<td rowspan="3" class='OS'>Android</td>
						<td><a href="https://play.google.com/store/apps/details?id=com.android.chrome">Chrome</a></td>
					</tr>
					<tr>
						<td><a href="https://play.google.com/store/apps/details?id=com.opera.browser">Opera</a></td>
					</tr>
					<tr>
						<td><a href="https://play.google.com/store/apps/details?id=com.sec.android.app.sbrowser">Samsung Internet Browser</a></td>
					</tr>
					<tr class='underline'>
						<td rowspan="1" class='OS'>Windows</td>
						<td><a href="https://www.google.com/intl/ja_jp/chrome/">Chrome</a></td>
					</tr>
					<tr class='underline'>
						<td rowspan="1" class='OS'>Mac</td>
						<td><a href="https://www.google.com/intl/ja_jp/chrome/">Chrome</a></td>
					</tr>
				</table>
			</div>
		</div>
	</div>
	<div id='TitleLayer'>
		<div id='Cbutton5'><a href="index.html"><img src="image/Controle.png" alt="コントローラー操作" id="ModeChangeButton"></a></div>
		<div class="Guide" id='Guide1'></div>
		<div id='TitleCenter'>
			<div id='TitleLogo'>
				<div id='SubTitle'>Command Controle</div>
				<img src='image/TitleLogo.png'>
			</div>
			<div id='TitleButton'>
				<div id='StartButton'>
					<input type="image" src='image/StartButton.png'>
					<div id='StartButtonLine'></div>
				</div>
				<div id='status'></div>
			</div>
		</div>
		<div id='TitleBottom'>
			<div id='Varsion'>v.1.1.1 - © 2021 PLEN Project Company Inc.</div>
		</div>
	</div>
	<div id='FullscreenArea'>
		<div id='CommandLayer'>
			<div id='Command'>
				<div id='LeftGroup'>
					<div id='Border1'></div>
					<div id='CommandTop'>
						<div id='TopButtonGroup'>
							<div id='TopButtonL'>
								<input type="image" class='TopButton' id='Cbutton1' src='image/Setting.png'>
							</div>
							<div id='TopButtonR'>
								<input type="image" class='TopButton' id='Cbutton4' src='image/Fullscreen-On.png'>
							</div>
						</div>
					</div>
					<div id='Reference'>
						<div class='Chapter'>オリジナル関数</div>
						<div class='ReferenceCode'>Motor(<value>％</value>);</div>
						<div class='ReferenceGuide'>DCモーターのパワーを変更します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>Motor(100);<br>Motor(0);<br>Motor(-100);</td>
									<td> → <br> → <br> → </td>
									<td>最大速度(100%)で前進<br>停止<br>最大速度(100%)で後進</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>Servo(<value>％</value>);</div>
						<div class='ReferenceGuide'>ステアリングサーボの角度を変更します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>Servo(100);<br>Servo(0);<br>Servo(-100);</td>
									<td> → <br> → <br> → </td>
									<td>最大角度(100%)で右折<br>直進<br>最大角度(100%)で左折</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>Port(<value>整数</value>,<value>整数</value>);</div>
						<div class='ReferenceGuide'>LEDポートのON/OFFを切り替えます<br>第一引数 - ポート番号<br>第二引数 - ON/OFF</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>Port(0,0);<br>Port(0,1);<br>Port(1,0);<br>Port(1,1);<br>Port(2,0);<br>Port(2,1);</td>
									<td> → <br> → <br> → <br> → <br> → <br> → </td>
									<td>両LED消灯<br>両LED点灯<br>左LED消灯<br>左LED点灯<br>右LED消灯<br>右LED点灯</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>Wait(<value>秒</value>);</div>
						<div class='ReferenceGuide'>処理を一時停止します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>Wait(0.1);<br>Wait(1);<br>Wait(10);</td>
									<td> → <br> → <br> → </td>
									<td>0.1秒待つ<br>1秒待つ<br>10秒待つ</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>Log(<value>文字列</value>);</div>
						<div class='ReferenceGuide'>文字列をコンソールに表示します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>Log("Hi!");</td>
									<td> → </td>
									<td>「Hi!」をコンソールに表示</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>Random(<value>整数1</value>,<value>整数2</value>);</div>
						<div class='ReferenceGuide'>整数1~整数2の乱数を返します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>var N = Random(1,3);</td>
									<td> → </td>
									<td>変数Nに1~3の整数が代入</td>
								</tr>
							</table>
						</div>
						<div class='Chapter'>JavaScript</div>
						<div class='ReferenceCode'>//<value>コメント文</value>
						</div>
						<div class='ReferenceGuide'>処理には影響しないコメント文を入力します</div>
						<div class='ReferenceExample'>
							//前進する<br>Motor(50);<br>//3秒後に左旋回<br>Wait(3);<br>Servo(-100);
						</div>
						<div class='ReferenceCode'>alert(<value>文字列</value>);</div>
						<div class='ReferenceGuide'>文字列をホップアップ表示します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>alert("Hi!");</td>
									<td> → </td>
									<td>「Hi!」ホップアップ表示</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>var <value>変数名</value>;</div>
						<div class='ReferenceGuide'>変数を定義します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>var N1 = 1;<br>var N2 = 2;<br><br>alert(N1 + N2);</td>
									<td><br><br><br> → </td>
									<td><br><br><br>3がホップアップ表示</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>if (<value>条件式</value>){<value>実行処理</value>}</div>
						<div class='ReferenceGuide'>if文を使用します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>if(Flag){<br>　//変数Flagはtrue<br>} else {<br>　//変数Flagはfalse<br>}</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>for (<value>変数</value>; <value>条件式</value>; <value>計算式</value>){<value>実行処理</value>}</div>
						<div class='ReferenceGuide'>for文を使用します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>for(var i = 0; i < 10; i++){<br>　//10回繰り返し<br>}</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>while (<value>条件式</value>){<value>実行処理</value>}</div>
						<div class='ReferenceGuide'>while文を使用します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>var N = 0;<br>while(N < 10){<br>　//10回繰り返し<br>N++<br>}</td>
								</tr>
							</table>
						</div>
						<div class='ReferenceCode'>function <value>関数名</value>(<value>引数</value>){<value>実行処理</value>}</div>
						<div class='ReferenceGuide'>関数を作成します</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>function Test(x,y){<br>return x + y;<br>}<br>Log(Test(1,2)); → コンソールに3表示</td>
								</tr>
							</table>
						</div>
						<div class='Chapter'>ローカルサーバー</div>
						<div class='ReferenceCode'>ReadLocalServer.<value>色</value>.<value>軸</value>();</div>
						<div class='ReferenceGuide'>ローカルサーバーからデータを受け取ります<br>受け取りに失敗するとnullを返します<br><br>呼び出しから取得まで時間差があります<br>繰り返し呼び出してください<br><br>
							<value> 色</value> : red, yellow, green, blue<br>
							<value> 軸</value> : x, y
						</div>
						<div class='ReferenceExample'>
							<table>
								<tr>
									<td>var YX = ReadLocalServer.yellow.x();</td>
									<td> → </td>
									<td>変数YXに黄色のX座標が代入</td>
								</tr>
							</table>
						</div>
					</div>
				</div>
				<div id="CenterGroup">
					<div id='Border1Line'></div>
					<div id='Border2Line'></div>
					<div id='CommandArea'>
						<div id='CommandButton'>
							<div id='CommandButtonMiddle'>
								<input type='image' id='CommandStopButton' src='image/CommandStop.png'>
								<input type='image' id='CommandStartButton' src='image/CommandStart.png'>
							</div>
						</div>
						<div id='Editer'>
							<textarea id='EditerTextArea' spellcheck="false" wrap="off" autofocus placeholder="スクリプトをここに入力"></textarea>
							<div id>
							</div>
						</div>
					</div>
				</div>
				<div id='RightGroup'>
					<div id='ConsoleArea'>
						<div id='Border2'></div>
						<div id='ConsoleTitle'>
							<div class='TextBottom'>コンソール</div>
						</div>
						<div id='Console'>
						</div>
					</div>
				</div>
			</div>
		</div>
		<div id='SettingLayer'>
			<div class="Guide" id='Guide2'></div>
			<div id='SettingList'>
				<table align="center" id="SettingTable">
					<tr class='row1'>
						<td id='SettingTitle' colspan="4">設定</td>
					</tr>
					<tr class='row4'>
						<td colspan="4">前後</td>
					</tr>
					<tr>
						<td class='col1'>最大速度</td>
						<td class='col2' id='Svalue1'>50%</td>
						<td class='col3' colspan="2"><input type="range" id='Sslider1' class='SettingSlider' min='20' max='100' value='60'></td>
					</tr>
					<tr class='row2'>
						<td colspan="4">ステアリング</td>
					</tr>
					<tr>
						<td class='col1'>最大角度</td>
						<td class='col2' id='Svalue2'>100%</td>
						<td class='col3' colspan="2"><input type="range" id='Sslider2' class='SettingSlider' min='20' max='100' value='100'></td>
					</tr>
					<tr>
						<td class='col1'>初期位置調整</td>
						<td class='col2' id='Svalue3'>0</td>
						<td class='col3' colspan="2"><input type="range" id='Sslider3' class='SettingSlider' min='-30' max='30' value='0'></td>
					</tr>
					<tr>
						<td class='col1'>反転</td>
						<td class='col2' id='Svalue10'>OFF</td>
						<td class='col4'><input type="range" id='Sslider10' class='SettingSlider' min='0' max='1' value='0'></td>
						<td></td>
					</tr>
					<tr class='row3'>
						<td colspan="4" class='col5'><input type='image' src='image/Enter.png' id='Sbutton1'></td>
					</tr>
				</table>
			</div>
		</div>
</body>

<script defer>
	//変数の定義
	const Lloading = document.getElementById('LoadingLayer');
	const LNoSupport = document.getElementById('NoSupportLayer');
	const LNoSupportContent = document.getElementById('NoSupportContent');
	const LTitle = document.getElementById('TitleLayer');
	const Lcontroller = document.getElementById('ControllerLayer');
	const Lcommand = document.getElementById('CommandLayer');
	const LoadingStatus = document.getElementById('LoadingText');
	const Lsetting = document.getElementById('SettingLayer');
	const ble = new BlueJelly();
	const StartButton = document.getElementById('StartButton');
	const Status = document.getElementById('status');
	const LoadingImageSource = document.getElementById('LoadingImageSource');
	const ModeChangeButton = document.getElementById('ModeChangeButton');
	const CButton1 = document.getElementById('Cbutton1');
	const CButton2 = document.getElementById('Cbutton2');
	const CButton3 = document.getElementById('Cbutton3');
	const CButton4 = document.getElementById('Cbutton4');
	const CButton5 = document.getElementById('Cbutton5');
	const SSlider1 = document.getElementById('Sslider1');
	const SSlider2 = document.getElementById('Sslider2');
	const SSlider3 = document.getElementById('Sslider3');
	const SSlider5 = document.getElementById('Sslider5');
	const SSlider6 = document.getElementById('Sslider6');
	const SSlider7 = document.getElementById('Sslider7');
	const SSlider8 = document.getElementById('Sslider8');
	const SSlider9 = document.getElementById('Sslider9');
	const SSlider10 = document.getElementById('Sslider10');
	const SButton1 = document.getElementById('Sbutton1');
	const SValue1 = document.getElementById('Svalue1');
	const SValue2 = document.getElementById('Svalue2');
	const SValue3 = document.getElementById('Svalue3');
	const SValue4 = document.getElementById('Svalue4');
	const SValue5 = document.getElementById('Svalue5');
	const SValue6 = document.getElementById('Svalue6');
	const SValue7 = document.getElementById('Svalue7');
	const SValue8 = document.getElementById('Svalue8');
	const SValue9 = document.getElementById('Svalue9');
	const SValue10 = document.getElementById('Svalue10');
	const GuideButton = document.getElementById('Guide1');
	const SettingGuideButton = document.getElementById('Guide2');

	var userAgent = window.navigator.userAgent.toLowerCase();
	var Support = false;
	var Device;
	var Browser;
	var stage = 0;
	var ReconnectCount = 0;
	var LoadingSpeed = 0.5;
	var LoadingAction;
	var Fullscreen = false;

	var PWMRange = 80;
	var PWMMin = 20;
	var ServoMaxBase = 255;
	var ServoMax = 255;
	var ServoRange = 80;
	var ServoAdj = 0;

	var SendTime = 50;

	var PWMValue = 127;
	var ServoValue = 127;
	var PortValue = 0;

	var RotateMaxBase = 40;
	var RotateMax = 40;
	var RotateMin = 0;
	var Rotate = true;
	var RotateSet = 0;
	var RotateBefore = false;

	var LightActive = false;
	var GyroActive = false;

	var KeyBoard = false;
	var Key = [];
	var KeyValue = [];


	//個人設定
	var Setting = [];
	var SettingString = [];
	var SettingNow = false;
	var FirstTime = 'false';


	//iosへの対応 (?<=) (?=)
	function GetRegex(mode, pattern1, pattern2, value, replace) {
		if (mode == 1) {
			//パターン1とパターン2の間
			var check1 = value.match(new RegExp(pattern1));
			var check2 = value.match(new RegExp(pattern2));

			if (check1 && check2) {
				var regex1 = new RegExp('^.*' + pattern1);
				var regex3 = new RegExp('^.*' + pattern2);
				var regex2 = new RegExp(pattern2 + '.*$');

				var count1 = value.match(regex1);
				var count2 = value.match(regex3);

				if (count1[0].length < count2[0].length) {
					var result = value.replace(regex1, '');
					result = result.replace(regex2, '');
					return result;
				} else {
					return null;
				}
			} else {
				return null;
			}
		} else if (mode == 2) {
			var regex = new RegExp('(' + pattern1 + ').*?(' + pattern2 + ')');
			if (value.match(regex)) {
				var result = value.replace(regex, '$1' + replace + '$2');
				return result;
			} else {
				return null;
			}
		} else {
			return null;
		}
	}


	//画像ドラッグ対策
	document.ondragstart = function() {
		return false;
	};

	//画面外はみ出し確認
	function DisplayOut() {
		Rotate = true;
		if (window.innerHeight >= LNoSupportContent.clientHeight) {
			LNoSupport.style.height = '100vh';
		} else {
			LNoSupport.style.height = '';
		}
	}

	//画面回転時の動作
	window.addEventListener("orientationchange", function() {
		setTimeout(function() {
			DisplayOut();
		}, 100);
	});

	function sleep(second) {
		return new Promise(resolve => {
			WaitId = setTimeout(() => {
				resolve()
			}, second * 1000)
		})
	}

	//初期動作
	window.onpageshow = function(e) {
		//safariの場合リロードする
		if (e.persisted) {
         window.location.reload();
     }

		//オフラインで使用可能にする
		if ('serviceWorker' in navigator) {
			//古いバージョンの削除
			if (navigator.onLine) {
				//オンラインの場合ServiceWorker削除
				navigator.serviceWorker.getRegistrations().then(function(registrations) {
					for (let registration of registrations) {
						registration.unregister();
					}
				}).catch(function(err) {
					// 登録失敗
					console.log('ServiceWorkerの削除に失敗しました。', err);
				});
			}

			navigator.serviceWorker.register('sw.js').then(function(registration) {
				// 登録成功
			}).catch(function(err) {
				// 登録失敗
				console.log('ServiceWorker の登録に失敗しました', err);
			});
		}

		stage = 0;

		if (userAgent.indexOf('iphone') != -1) {
			//iphone
			Support = false;
			Device = 'ios';
		} else if (userAgent.indexOf('ipad') != -1) {
			//ipad
			Support = false;
			Device = 'ios';
		} else if (userAgent.indexOf('android') != -1) {
			if (userAgent.indexOf('mobile') != -1) {
				//Android
				Support = true;
				Device = 'Android';
			} else {
				//AndroidTablet
				Support = true;
				Device = 'Android';
			}
		} else {
			//PC
			Support = true;
			Device = 'PC';
		}

		if (Support) {
			if (userAgent.indexOf('msie') != -1 ||
				userAgent.indexOf('trident') != -1) {
				//IE
				Support = false;
				Browser = 'IE';
			} else if (userAgent.indexOf('edge') != -1) {
				//edge
				Support = false;
				Browser = 'Edge';
			} else if (userAgent.indexOf('opr') != -1) {
				//Opera
				if (Device == 'PC') {
					Support = false;
				} else {
					Support = true;
				}
				Browser = 'Opera';
			} else if (userAgent.indexOf('chrome') != -1) {
				//chrome
				Support = true;
				Browser = 'Chrome';
			} else if (userAgent.indexOf('safari') != -1) {
				//Safari
				Support = false;
				Browser = 'Safari';
			} else if (userAgent.indexOf('firefox') != -1) {
				//FireFox
				Support = false;
				Browser = 'FireFox';
			} else if (userAgent.indexOf('opera') != -1) {
				//Opera
				if (Device == 'PC') {
					Support = false;
				} else {
					Support = true;
				}
				Browser = 'Opera';
			} else if (userAgent.indexOf('samsungbrowser') != -1) {
				//Samsung Internet Browser
				Support = true;
				Browser = 'SamsungInternetBrowser';
			} else {
				//Others
				Support = false;
				Browser = 'Unknown';
			}
		} else {
			//例外
			if (userAgent.indexOf('bluefy') != -1) {
				//Bluefy
				Support = true;
				Browser = 'Bluefy';
			}
		}

		//UUIDの登録
		ble.setUUID("UUID1", "389caaf0-843f-4d3b-959d-c954cce14655", "389caaf1-843f-4d3b-959d-c954cce14655");
		ble.setUUID("UUID2", "389caaf0-843f-4d3b-959d-c954cce14655", "389caaf2-843f-4d3b-959d-c954cce14655");
		ble.setUUID("UUID3", "389caaf0-843f-4d3b-959d-c954cce14655", "389caaf3-843f-4d3b-959d-c954cce14655");
		ble.setUUID("UUID4", "389caaf0-843f-4d3b-959d-c954cce14655", "389caaf4-843f-4d3b-959d-c954cce14655");
		ble.setUUID("UUID5", "389caaf0-843f-4d3b-959d-c954cce14655", "389caaf5-843f-4d3b-959d-c954cce14655");
		ble.setUUID("UUID6", "389caaf0-843f-4d3b-959d-c954cce14655", "389caaff-843f-4d3b-959d-c954cce14655");

		//セーブデータの存在確認
		if (localStorage.getItem('SaveData') == null) {
			//プリセットを登録する
			localStorage.setItem('SaveData','60,80,0,0,50,100,0,0,ArrowUp,ArrowDown,ArrowLeft,ArrowRight, ,0,true,0,,100,0,1');
		}
		Setting = localStorage.getItem('SaveData').split(',');

		if (Setting.length != 20) {
			//プリセットを登録する
			localStorage.setItem('SaveData','60,80,0,0,50,100,0,0,ArrowUp,ArrowDown,ArrowLeft,ArrowRight, ,0,true,0,,100,0,1');
			Setting = localStorage.getItem('SaveData').split(',');
		}


		//コマンド用セーブデータの存在確認
		if (localStorage.getItem('SaveData2') == null) {
			//プリセットを登録する
			localStorage.setItem('SaveData2', '20,20');
		}
		Setting2 = localStorage.getItem('SaveData2').split(',');

		if (Setting2.length != 2) {
			//プリセットを登録する
			localStorage.setItem('SaveData2', '20,20');
			Setting2 = localStorage.getItem('SaveData2').split(',');
		}

		NowBorder1 = Setting2[0];
		NowBorder3 = Setting2[1];
		NowBorder2 = 100 - NowBorder1 - NowBorder3;

		if (localStorage.getItem('SaveData3') != null) {
			var getOriginalCode = JSON.parse(localStorage.getItem('SaveData3'));
			Editer.value = getOriginalCode['savecode'];
		}

		//設定画面の値変更
		SSlider1.value = Setting[0];
		SValue1.innerHTML = SSlider1.value + '%';
		SSlider2.value = Setting[1];
		SValue2.innerHTML = SSlider2.value + '%';
		SSlider3.value = Setting[2];
		if (SSlider3.value > 0) {
			SValue3.innerHTML = '+' + SSlider3.value;
		} else {
			SValue3.innerHTML = SSlider3.value;
		}

		var DisplayGPSwarning = false;
		if (Setting[14] == 'true') {
			DisplayGPSwarning = 'true';
		}
		if (Support == false || Device == 'ios') {
			DisplayGPSwarning = false;
		}

		SSlider10.value = Setting[15];
		if (SSlider10.value == 0) {
			SValue10.innerHTML = 'OFF';
		} else {
			SValue10.innerHTML = 'ON';
		}

		//設定を反映
		SettingSet();

		//データ送信開始
		SendData();

		//サーボ初期位置へ
		ServoControll(100);

		if (Device == 'PC'){
			GuideButton.innerHTML = '<a href="pdf/PC-Guide.pdf" target="_blank"><img src="image/Question.png" alt="説明書"></a>';
			SettingGuideButton.innerHTML = '<a href="pdf/PC-Setting.pdf" target="_blank"><img src="image/Question.png" alt="設定ガイド"></a>';
		}else{
			GuideButton.innerHTML = '<a href="pdf/Mobile-Guide.pdf" target="_blank"><img src="image/Question.png" alt="説明書"></a>';
			SettingGuideButton.innerHTML = '<a href="pdf/Mobile-Setting.pdf" target="_blank"><img src="image/Question.png" alt="設定ガイド"></a>';
		}

		if (Device == 'Android' || Device == 'ios') {
			//hoverを無効にする
			StartButton.style.opacity = '1';
			CButton1.style.opacity = '1';
			CButton4.style.opacity = '1';

			if (Device == 'ios') {
				//フルスクリーンを無効にする
				CButton4.style.display = "none";
			}
		}

		if (DisplayGPSwarning) {
			//Status.innerHTML = '<font color="red">初回利用時は位置情報の権限設定をご確認ください</font><br><a href="pdf/Permission' + Device + Browser + '.pdf" target="_blank">ブラウザ権限の設定手順</a>';
		}

		if (Support) {
			//ローディング画面の削除
			Lcommand.style.display = 'none';
			Lsetting.style.display = 'none';
			LNoSupport.style.display = 'none';
			LTitle.style.display = '';
		} else {
			//非対応ブラウザ
			DisplayOut();
			//ローディング画面の削除
			Lcommand.style.display = 'none';
			Lsetting.style.display = 'none';
			LTitle.style.display = 'none';
			LNoSupport.style.display = '';
		}
		Lloading.style.opacity = 1;
		DestroyLoading();
	}

	//ローディング画面の表示
	function DisplayLoading(FinishFunction) {
		clearTimeout(LoadingAction);
		Lloading.style.display = '';
		if (Lloading.style.opacity < 0) {
			Lloading.style.opacity = 0;
			Lloading.style.display = 'none';
			LoadingAction = setTimeout(function() {
				DisplayLoading(FinishFunction)
			}, 10);
		} else if (Lloading.style.opacity >= 1) {
			Lloading.style.opacity = 1;
			if (FinishFunction != null) {
				FinishFunction();
			}
		} else {
			Lloading.style.opacity = Number(Lloading.style.opacity) + 1/(LoadingSpeed*100);
			LoadingAction = setTimeout(function() {
				DisplayLoading(FinishFunction)
			}, 10);
		}
	}

	//ローディング画面の削除
	function DestroyLoading(FinishFunction) {
		clearTimeout(LoadingAction);
		Lloading.style.display = '';
		if (Lloading.style.opacity > 1) {
			Lloading.style.opacity = 1;
			LoadingAction = setTimeout(function() {
				DestroyLoading(FinishFunction)
			}, 10);
		} else if (Lloading.style.opacity <= 0) {
			Lloading.style.opacity = 0;
			Lloading.style.display = 'none';
			if (FinishFunction != null) {
				FinishFunction();
			}
		} else {
			Lloading.style.opacity = Number(Lloading.style.opacity) - 1/(LoadingSpeed*100);
			LoadingAction = setTimeout(function() {
				DestroyLoading(FinishFunction)
			}, 10);
		}
	}

	//スタートボタン
	StartButton.addEventListener('click', function() {
		StartButton.disabled = true;
		//ローディング画面
		DisplayLoading(ScanStart);
	});

	//スキャン開始
	function ScanStart() {
		stage = 1;
		ble.scan('UUID6');
	}


	//スキャン成功
	ble.onScan = function(deviceName) {
		//接続する
		stage = 2;
		ble.connectGATT('UUID6');
	}

	//接続完了
	ble.onConnectGATT = function(uuid) {
		if(stage == 4){
			if(BLEerrorFlag){
				if(CommandNow){
					Log('ESPRacerと接続しました');
				}else{
					Log('ESPRacerと接続しました<br><br>');
				}
			}
			BLEerrorFlag = false;
		}else{
			stage = 3;
			setTimeout(function() {
				OnConnectFinish();
			}, 1000);
		}
	}

	//ESPRacer切断時
	ble.onDisconnect = function() {
		if(stage == 4){
			if(BLEerrorFlag == false){
				Log('<red>ESPRacerから切断されました！</red><br>再接続中...');
			}
			BLEerrorFlag = true;
		}else{
			//接続する
			stage = 2;
			ble.connectGATT('UUID6');
		}
	}

	function OnConnectFinish() {
		if (stage == 3) {
			if (FirstTime == 'true') {
				FirstTime = 'false';
				Save();
			}

			//コントロール画面の表示
			Lcommand.style.display = '';
			//タイトル画面の削除
			LTitle.style.display = 'none';
			//ローディング画面の削除
			DestroyLoading(null);
			stage = 4;
		}
	};

	//コントローラー

	//設定ボタン
	CButton1.addEventListener('click', function() {
		SettingNow = true;
		KeyBoard = false;
		GyroActive = false;
		PWM(100);
		ServoControll(100);
		if (CButton3) {
			CButton3.setAttribute('src', 'image/GyroOn.png');
		} else {
			CommandFinish();
		}

		Lsetting.style.display = '';
		Lcommand.style.display = 'none';
	});

	//フルスクリーン
	CButton4.addEventListener('click', function() {
		var target = FullscreenArea;

		if (Fullscreen) {
			if (document.webkitCancelFullScreen) {
				document.webkitCancelFullScreen(); //Chrome15+, Safari5.1+, Opera15+
			} else if (document.mozCancelFullScreen) {
				document.mozCancelFullScreen(); //FF10+
			} else if (document.msExitFullscreen) {
				document.msExitFullscreen(); //IE11+
			} else if (document.cancelFullScreen) {
				document.cancelFullScreen(); //Gecko:FullScreenAPI仕様
			} else if (document.exitFullscreen) {
				document.exitFullscreen(); // HTML5 Fullscreen API仕様
			}
		} else {
			if (target.webkitRequestFullscreen) {
				target.webkitRequestFullscreen(); //Chrome15+, Safari5.1+, Opera15+
			} else if (target.mozRequestFullScreen) {
				target.mozRequestFullScreen(); //FF10+
			} else if (target.msRequestFullscreen) {
				target.msRequestFullscreen(); //IE11+
			} else if (target.requestFullscreen) {
				target.requestFullscreen(); // HTML5 Fullscreen API仕様
			} else {
				alert('ご利用のブラウザはフルスクリーン操作に対応していません');
				return;
			}
		}
	});

	document.onfullscreenchange = document.onmozfullscreenchange = document.onwebkitfullscreenchange = document.onmsfullscreenchange = function(event) {
		if (Fullscreen) {
			Fullscreen = false;
			CButton4.setAttribute('src', 'image/Fullscreen-On.png');
		} else {
			Fullscreen = true;
			CButton4.setAttribute('src', 'image/Fullscreen-Off.png');
		}
	};

	//PWM
	function PWM(value) {

		var check1;
		var check2;
		var check3;

		if (value == 100) {
			check2 = 127;
		} else if (value > 100) {
			check1 = PWMRange - PWMMin;
			value -= 100;
			check2 = value / 100 * check1 + 127 + PWMMin;
		} else {
			check1 = PWMRange - PWMMin;
			check3 = 100 - value;
			check2 = 127 - check1 / 100 * check3 - PWMMin;
		}

		PWMValue = check2;
	};

	//Servo
	function ServoControll(value) {
		var check1;
		var check2;
		var check3;

		if (value >= 100) {
			check1 = ServoRange;
			value -= 100;
			check2 = value / 100 * check1 + (127 + ServoAdj);
		} else {
			check1 = ServoRange;
			check3 = 100 - value;
			check2 = (127 + ServoAdj) - check1 / 100 * check3;
		}

		ServoValue = check2;
	};

	//データ送信
	var TimeCount = 0;

	function SendData() {
		if (stage >= 3) {
			//上限の数字にしない
			if (ServoValue < 5) {
				ServoValue = 5;
			} else if (ServoValue > 250) {
				ServoValue = 250;
			}
			if (PWMValue < 5) {
				PWMValue = 5;
			} else if (PWMValue > 250) {
				PWMValue = 250;
			}

			//操作反転
			var SendServoValue = ServoValue;
			if (SSlider10.value == 1) {
				SendServoValue = 127 + (127 - ServoValue);
			}
			WriteArray = [parseInt(PWMValue), parseInt(PWMValue), parseInt(PortValue), parseInt(SendServoValue), parseInt(SendServoValue), parseInt(SendServoValue), parseInt(SendServoValue)];
			ble.write('UUID5', WriteArray);
		}

		//デバッグ用
		//console.log(parseInt(PortValue));
		//console.log(parseInt(ServoValue));
		//console.log(parseInt(PWMValue));
		//console.log('============');

		//ローディングテキストの変更
		var text1;

		if (TimeCount >= 4000) {
			text1 = '';
			TimeCount = SendTime;
		} else if (TimeCount >= 3000) {
			text1 = '...';
			TimeCount += SendTime;
		} else if (TimeCount >= 2000) {
			text1 = '..';
			TimeCount += SendTime;
		} else if (TimeCount >= 1000) {
			text1 = '.';
			TimeCount += SendTime;
		} else {
			text1 = '';
			TimeCount += SendTime;
		}

		var text2;
		if (stage == 0) {
			text1 = '';
			text2 = '';
		} else if (stage == 1) {
			text2 = 'Pairing';
		} else if (stage == 2) {
			text2 = 'Certifying';
		} else if (stage == 3 || stage == 4) {
			text1 = '';
			text2 = 'Complete!';
		} else {
			text2 = 'Loading';
		}
		LoadingStatus.innerHTML = text2 + text1;

		setTimeout(function() {
			SendData()
		}, SendTime);
	}

	//設定画面
	SSlider1.addEventListener('input', function() {
		SValue1.innerHTML = SSlider1.value + '%';
		PWMValue = 127 + 127 * SSlider1.value / 100;
	});
	SSlider1.addEventListener('change', function() {
		Save();
		PWMValue = 127;
	});
	SSlider2.addEventListener('input', function() {
		SValue2.innerHTML = SSlider2.value + '%';
		var check1 = ServoMaxBase - (127 + Number(SSlider3.value));
		if (check1 < 0) {
			check1 = 0;
		}
		ServoValue = 127 + Number(SSlider3.value) + check1 * Number(SSlider2.value) / 100;
	});
	SSlider2.addEventListener('change', function() {
		Save();
		ServoValue = 127 + Number(SSlider3.value);
	});
	SSlider3.addEventListener('input', function() {
		if (SSlider3.value > 0) {
			SValue3.innerHTML = '+' + SSlider3.value;
		} else {
			SValue3.innerHTML = SSlider3.value;
		}
		ServoValue = 127 + Number(SSlider3.value);
	});
	SSlider3.addEventListener('change', function() {
		Save();
		ServoValue = 127 + Number(SSlider3.value);
	});
	SSlider10.addEventListener('input', function() {
		if (SSlider10.value == 0) {
			SValue10.innerHTML = 'OFF';
		} else {
			SValue10.innerHTML = 'ON';
		}
	});
	SSlider10.addEventListener('change', function() {
		Save();
	});

	//モード切り替えボタン
	preventModeChangeButton = true;
	ModeChangeButton.addEventListener('click', function(e) {
		if(preventModeChangeButton){
			//リンク遷移を無効にする
			e.preventDefault();
			//ローディング画面に移項する
			LoadingImageSource.style.animation = 'initial';
			stage = 0;
			DisplayLoading(OnFinishModeChangeButton);
		}
	});
	beforeLoadingLotation = 0;
	function OnFinishModeChangeButton(){
		preventModeChangeButton = false;
		ModeChangeButton.click();
	}

	//Enterボタン
	SButton1.addEventListener('click', function() {
		SettingNow = false;
		SettingSet();
		Lsetting.style.opacity = '1';
		if (RotateBefore) {
			GyroActive = true;
			HSlider.disabled = true;
			CButton3.setAttribute('src', 'image/GyroOff.png');
		}
		Lcommand.style.display = '';
		Lsetting.style.display = 'none';
	});

	function Save() {
		Setting = localStorage.getItem('SaveData').split(',');
		localStorage.setItem('SaveData', SSlider1.value + ',' + SSlider2.value + ',' + SSlider3.value + ',' + '0' + ',' + Setting[4] + ',' + Setting[5] + ',' + Setting[6] + ',' + Setting[7] + ',' + Setting[8] + ',' + Setting[9] + ',' + Setting[10] + ',' +
			Setting[11] + ',' + Setting[12] + ',' + 'false' + ',' + SSlider10.value + ',' + Setting[16] + ',' + Setting[17] + ',' + Setting[18] + ',' + Setting[19]);
	};

	//設定データを反映させる
	function SettingSet() {
		Setting = localStorage.getItem('SaveData').split(',').map(Number);
		SettingString = localStorage.getItem('SaveData').split(',');
		PWMMin = 30 * Setting[0] / 100
		PWMRange = 127 * Setting[0] / 100;
		ServoAdj = Setting[2];
		//ServoMax = ServoMaxBase + Setting[3];
		var check1 = ServoMaxBase - (127 + ServoAdj);
		if (check1 < 0) {
			check1 = 0;
		}
		ServoRange = check1 * Setting[1] / 100;

		if ((127 + ServoAdj - ServoRange) < 0) {
			ServoRange = 127 + ServoAdj;
		}

		var max = RotateMaxBase * (110 - Setting[4]) / 100;
		var min = 10 * (110 - Setting[4]) / 100;
		RotateMax = max;
		RotateMin = min;

		Area1FontSizeSet();
	};

	//エラー時
	ble.onError = function(error) {
		if (error.toString().search(/Web Bluetooth is not supported/) != -1 || error.toString().search(/Bluetooth Low Energy not available/) != -1) {
			//非対応ブラウザ
			DisplayOut();
			//ローディング画面の削除
			Lcommand.style.display = 'none';
			Lsetting.style.display = 'none';
			LTitle.style.display = 'none';
			LNoSupport.style.display = '';
			DestroyLoading();
		} else {
			if (stage == 1) {
				//スキャン失敗  →  タイトル
				Lcommand.style.display = 'none';
				LTitle.style.display = '';
				DestroyLoading();
				stage = 0;
				StartButton.disabled = false;
				Status.innerHTML = '<font color="red">ペアリングに失敗しました</font><br>"ESPRacer"を選択し、ペア設定を行ってください';
			} else if (stage == 2) {
				//接続失敗  →  再接続
				if (ReconnectCount < 5) {
					ReconnectCount++;
					ble.connectGATT('UUID6');
				} else {
					Lcommand.style.display = 'none';
					LTitle.style.display = '';
					DestroyLoading();
					ble.reset();
					stage = 0;
					StartButton.disabled = false;
					Status.innerHTML = '<font color="red">認証に失敗しました</font><br>正しく"ESPRacer"を選択できているか確認してください';
				}
			}
		}
	}

	//エディター機能
	//変数の定義
	const CommandButtonGroup = document.getElementById('CommandButtonMiddle');
	const CommandStart = document.getElementById('CommandStartButton');
	const CommandStop = document.getElementById('CommandStopButton');
	const Editer = document.getElementById('EditerTextArea');
	const Console = document.getElementById('Console');
	const Border1 = document.getElementById('Border1');
	const Border2 = document.getElementById('Border2');
	const Area1 = document.getElementById('LeftGroup');
	const Area2 = document.getElementById('CenterGroup');
	const Area3 = document.getElementById('RightGroup');
	const Chapter = document.getElementsByClassName('Chapter');
	const ReferenceCode = document.getElementsByClassName('ReferenceCode');
	const ReferenceGuide = document.getElementsByClassName('ReferenceGuide');
	const ReferenceExample = document.getElementsByClassName('ReferenceExample');

	//セキュリティ
	const ExistFunctionList = ['DisplayOut', 'DisplayLoading', 'DestroyLoading', 'ScanStart', 'OnConnectFinish', 'PWM', 'ServoControll', 'SendData', 'Save', 'SettingSet', 'CommandFinish', 'OnClickStart', 'StartCommand', 'Loop', 'ErrorOccurd',
		'ErrorSleep', 'ReturnLocalServerValue', 'ErrorCheck', 'Finish'
	];
	const ExistOriginalFunctionList = ['Motor', 'Servo', 'Port', 'ReadLocalServer', 'Wait', 'Log', 'Random', 'ReadLocalServer', 'RequestLocalServer'];
	const ExistVariableList = ['userAgent', 'Support', 'Device', 'Browser', 'stage', 'ReconnectCount', 'LoadingSpeed', 'Fullscreen', 'PWMRange', 'PWMMin', 'ServoMaxBase', 'ServoMax', 'ServoRange', 'ServoAdj', 'SSendTime', 'PWMValue', 'PortValue',
		'RotateMaxBase', 'RotateMin', 'Rotate', 'RotateSet', 'RoRotateBefore', 'LightActive', 'GyroActive', 'KeyBoard', 'Key', 'KeyValue', 'Setting', 'SettiSettingString', 'SettingNow', 'FirstTime', 'ScriptList', 'ScriptCheckList', 'VariableList',
		'ValueList',
		'StringList', 'FinishFlag', 'click1', 'click2', 'Traces', 'ConsoleLog', 'MoveFlag', 'NowBorder1', 'NowBorder2', 'NowBorder3', 'StartX1', 'StartX2', 'BeforeX', 'WaitId', 'CommandAction', 'ActionCommand', 'VariableString', 'LoopCount',
		'LoopFunctionList', 'LoopWaitList', 'ForVariableList', 'StartCommand1', 'ErrorMessageStartCommand', 'ErrorTypeStartCommand', 'StacktraseCheckStartCommand', 'lineStartCommand', 'positionStartCommand', 'IfFlag', 'EndlessLoopCount', 'ErrorHappend',
		'LoopBreakFlag', 'CommandNow', 'HttpServerValueColor', 'HttpServerValueX', 'HttpServerValueY', 'BLEerrorFlag', 'TouchAdj'
	];

	var BLEerrorFlag = false;

	var Traces = [];
	var ScriptList = [];
	var ScriptCheckList = [];
	var VariableList = [];
	var ForVariableList = [];
	var ValueList = [];
	var StringScript;
	var FinishFlag = 0;
	var click1 = true;
	var click2 = true;
	var ConsoleLog = '';
	var VariableString = '';

	var raw_stacktrace;
	var stacktrace;

	var MoveFlag = 0;
	var NowBorder1 = 20;
	var NowBorder2 = 60;
	var NowBorder3 = 20;
	var StartX1 = 0;
	var StartX2 = 0;
	var BeforeX = 0;
	var TouchAdj = 0;

	var CommandAction = false;
	var WaitId;

	var LoopFunctionList = [];
	var LoopWaitList = [];
	var LoopCount = 0;
	var IfFlag = 0;

	var EndlessLoopCount;
	var ErrorHappend = false;
	var CommandNow = false;

	var LoopBreakFlag = false;


	//コマンド開始ボタン
	CommandStart.addEventListener('click', function() {
		if (click1 && FinishFlag == 0 && CommandNow == false) {
			click1 = false;
			OnClickStart();
			setTimeout(click1 = true, 1000);
		}
	});

	//コマンド停止ボタン
	CommandStop.addEventListener('click', function() {
		if (click2) {
			click2 = false;
			CommandFinish();
			setTimeout(click2 = true, 1000);
		}
	});

	function CommandFinish() {
		CommandNow = false;

		//初期位置に戻す
		PortValue = 0;
		ServoControll(100);
		PWM(100);

		//ループを中断させる
		clearTimeout(WaitId);
		FinishFlag = 0;
		LoopCount = 0;

		if (CommandAction) {
			var now = new Date();
			var min = now.getMinutes();
			var Sec = now.getSeconds();
			var Time = '[' + min + '分' + Sec + '秒]';

			if(BLEerrorFlag){
				Log(Time + ' - 処理中断 (<red>ESPRacerと未接続</red>)<br><br>');
			}else{
				Log(Time + ' - 処理中断<br><br>');
			}

			CommandAction = false;
		}
	}

	function OnClickStart() {
		LoopCount = -1;
		EndlessLoopCount = 0;
		ErrorHappend = false;
		CommandNow = true;

		VariableList = [];
		ValueList = [];
		ForVariableList = [];
		VariableString = '';

		HttpServerValueColor = [];
		HttpServerValueX = [];
		HttpServerValueY = [];

		var OriginalCode = {
			savecode: Editer.value
		};
		localStorage.setItem('SaveData3', JSON.stringify(OriginalCode));

		VariableList = [];
		ValueList = [];

		//シングルクォーテーションはダブルクォーテーションに変換
		var check = Editer.value.replace(new RegExp("'", 'g'), '"');

		//セミコロンを改行コードに変換
		check = check.replace(/;/g, ';\n');

		//内容確認
		ScriptList = check.split('\n');

		//コマンドの抽出
		var CommandOK = true;
		var CommandOK2 = true;
		var ErrorFunction = '';
		var ErrorVariable = '';

		for (var i = 0; i < ScriptList.length; i++) {
			ScriptList[i] = ScriptList[i].replace(/[/][/].*$/g, '');

			//チェックリスト
			ScriptCheckList[i] = ScriptList[i].replace(/\s/g, '');
			ScriptCheckList[i] = ScriptCheckList[i].replace(/".*?"/g, '""');

			//文末に;か{}がついているか
			var LastCheck1 = ScriptCheckList[i].match(/^\s*$/g);
			var LastCheck2 = ScriptCheckList[i].match(/[{};]$/g);
			if (LastCheck1 == null && LastCheck2 == null) {
				ScriptList[i] = ScriptList[i] + ';';
			}

			//letをvarに変換
			var LetCheck1 = ScriptList[i].match(/let\s/g);
			var LetCheck2 = ScriptList[i].match(/".*?let\s/g);
			if (LetCheck1 != null && LetCheck2 == null) {
				ScriptList[i] = ScriptList[i].replace(/let\s/g, 'var ');
				ScriptCheckList[i] = ScriptCheckList[i].replace(/let/g, 'var');
			}

			//MicroBit関連
			var RoopFlag = true;
			while (RoopFlag) {
				if (ScriptList[i].match(/ESPRacer\.value.\(.*?\)/g)) {
					//var ValueCheck1 = ScriptList[i].match(/(?<=).*?(?=)/g);
					var ValueCheck1 = GetRegex(1, "ESPRacer\\.value.\\(", "\\)", ScriptList[i], "");
					var ValueCheck2 = ScriptList[i].match(/ESPRacer\.value.\(.*?\)/);
					if (ValueCheck1) {
						ScriptList[i] = ScriptList[i].replace(ValueCheck2[0], ValueCheck1);
					} else {
						RoopFlag = false;
					}
				} else {
					RoopFlag = false;
				}
			}
			if (ScriptCheckList[i].match(/^ESPRacer[.]/g)) {
				ScriptList[i] = ScriptList[i].replace(/ESPRacer[.]/g, '');
			}
			if (ScriptCheckList[i].match(/^basic[.]showString/g)) {
				ScriptList[i] = ScriptList[i].replace(/basic[.]showString/g, 'Log');
			}
			if (ScriptCheckList[i].match(/^basic[.]showNumber/g)) {
				ScriptList[i] = ScriptList[i].replace(/basic[.]showNumber/g, 'Log');
			}
			//if (ScriptCheckList[i].match(/(?<=basic[.]pause\().*?(?=\))/g)) {
			if (GetRegex(1, "basic\\.pause\\(", "\\),ScriptCheckList[i]", "")) {
				//var Secounds = ScriptCheckList[i].match(/(?<=basic[.]pause\().*?(?=\))/g);
				var Secounds = GetRegex(1, "basic\\.pause\\(", "\\)", ScriptCheckList[i], "");
				if (Number(Secounds[0]) && Number(Secounds[0]) > 0) {
					ScriptList[i] = ScriptList[i].replace(/basic[.]pause\(.*?\)/g, 'Wait(' + Number(Secounds[0]) / 1000 + ')');
				} else {
					ScriptList[i] = ScriptList[i].replace(/basic[.]pause\(.*?\)/g, 'Wait(0)');
				}
			}
			if (ScriptCheckList[i].match(/Math[.]randomRange\(.*?\)/g)) {
				ScriptList[i] = ScriptList[i].replace(/Math[.]randomRange\(/g, 'Random(');
			}

			//関数チェックを行う
			if (ScriptCheckList[i].match(/^\s*[A-Z,a-z,0-9]+\(.*\)/g)) {

				var ScriptCheck = ScriptCheckList[i].match(/.*?\(/g);

				for (var n = 0; n < ScriptCheck.length; n++) {
					var ScriptCheck2 = ScriptCheck[n].replace('(', '');
					if (ExistFunctionList.indexOf(ScriptCheck2) != -1) {
						ErrorFunction = ScriptCheck2;
						CommandOK = false;
					}
				}
			}

			//変数チェックを行う
			if (ScriptCheckList[i].match(/[a-z|A-Z|0-9]*=/g)) {

				var ScriptCheck = ScriptCheckList[i].match(/[a-z|A-Z|0-9]*=/g);

				for (var n = 0; n < ScriptCheck.length; n++) {
					var ScriptCheck1 = ScriptCheck[n].replace('var', '');
					ScriptCheck1 = ScriptCheck1.replace('=', '');

					if (ExistVariableList.indexOf(ScriptCheck1) != -1 || ExistFunctionList.indexOf(ScriptCheck1) != -1 || ExistOriginalFunctionList.indexOf(ScriptCheck1) != -1) {
						ErrorVariable = ScriptCheck1;
						CommandOK2 = false;
					}
				}
			}

			//Wait関数を書き換える
			if (ScriptCheckList[i].match(/^\s*Wait\(.*\)/g)) {
				ScriptList[i] = ScriptList[i].replace(/(^\s*Wait)(\(.*\))/g, 'await sleep$2');
			}
		}

		if (CommandOK == false) {
			//使用できない関数あり
			ErrorOccurd();
			Log('<red>' + ErrorFunction + '();</red>は使用できない関数です！<br><br>');
			CommandFinish();
		}

		if (CommandOK2 == false) {
			//使用できない変数あり
			ErrorOccurd();
			Log('var <red>' + ErrorVariable + '</red>;は使用できない変数です！<br>変数名を変更してください<br><br>');
			CommandFinish();
		}

		if (CommandOK && CommandOK2) {
			var now = new Date();
			var min = now.getMinutes();
			var Sec = now.getSeconds();
			var Time = '[' + min + '分' + Sec + '秒]';

			if(BLEerrorFlag){
				Log(Time + ' - 処理開始 (<red>ESPRacerと未接続</red>)');
			}else{
				Log(Time + ' - 処理開始');
			}

			CommandAction = true;

			//配列を文字列に変換
			StringScript = ScriptList.join('');

			CommandExe();
		}
	};

	function CommandExe() {
		try {
			eval("(async (error, result) => {try {" + StringScript + "Finish();} catch (e) {ErrorCheck(e);}})()");
		} catch (e) {
			ErrorCheck(e);
		}
	};

	function ErrorCheck(e) {
		var ErrorTypeStartCommand = '';
		var ErrorMessageStartCommand = '';

		ErrorHappend = true;

		console.log(e);

		if (e instanceof TypeError) {
			ErrorTypeStartCommand = '変数型エラー';
			ErrorMessageStartCommand = '　変数の代入先が不正です<br>　変数を確認してください';
		} else if (e instanceof RangeError) {
			ErrorTypeStartCommand = '範囲エラー';
			ErrorMessageStartCommand = '　定義域を越しています<br>　計算式を確認してください';
		} else if (e instanceof ReferenceError) {
			ErrorTypeStartCommand = '参照エラー';
			ErrorMessageStartCommand = '　変数の参照に失敗しました<br>　変数を確認してください';
		} else if (e instanceof SyntaxError) {
			ErrorTypeStartCommand = '構文エラー';
			ErrorMessageStartCommand = '　構文に間違いがあります<br>　スクリプトの構文を確認してください';
		} else {
			ErrorTypeStartCommand = 'エラー';
			ErrorMessageStartCommand = '　エラーが発生しました<br>　スクリプトを確認してください';
		}

		stacktrace = e.stack.split(/\r\n?|\n/).slice(1);

		var StacktraseCheckStartCommand = [];
		var lineStartCommand = -1;
		var positionStartCommand = -1;

		for (var i = 0; i < stacktrace.length; i++) {
			if (stacktrace[i].indexOf('eval') != -1) {
				StacktraseCheckStartCommand = stacktrace[i].split('<anonymous>');
				StacktraseCheckStartCommand = StacktraseCheckStartCommand[1].split(':');
				lineStartCommand = StacktraseCheckStartCommand[1];
				positionStartCommand = StacktraseCheckStartCommand[2].replace(')', '');
				break;
			}
		}

		ErrorOccurd();
		CommandAction = false;
		CommandFinish();

		positionStartCommand -= 32;

		if (positionStartCommand >= 0) {
			Log('<red> ' + ErrorTypeStartCommand + '</red><br>' + ErrorMessageStartCommand);

			var ProblemScript = '';
			ProblemScript = StringScript;

			var Part1 = ProblemScript.substr(0, positionStartCommand - 1);
			var Part2 = ProblemScript.substr(positionStartCommand - 1, ProblemScript.length);
			var PartArray = [];
			if (Part2.match(/^[^A-X,^a-x,^0-9]/g)) {
				PartArray[0] = Part2.match(/^[^A-X,^a-x,^0-9]*[A-X,a-x,0-9]*/g);
			} else {
				PartArray = Part2.split(/[^A-X,^a-x,^0-9]/g);
			}
			if (PartArray[0])
				var Part3 = Part2.substr(Number(String(PartArray[0]).length), Part2.length);

			Log('　エラー発生箇所 : ' + '<red>' + PartArray[0] + '</red>' + '<br>　　' + Part1 + '<red>' + PartArray[0] + '</red>' + Part3 + '<br>');
			CommandAction = true;
			CommandFinish();
		} else {
			Log('<red> ' + ErrorTypeStartCommand + '</red><br>' + ErrorMessageStartCommand + '<br>');
			CommandAction = true;
			CommandFinish();
		}
	};

	function ErrorOccurd() {
		var now = new Date();
		var min = now.getMinutes();
		var Sec = now.getSeconds();
		var Time = '[' + min + '分' + Sec + '秒]';

		Log('<red>' + Time + ' - エラー発生</red>');
	}

	function Finish() {
		var now = new Date();
		var min = now.getMinutes();
		var Sec = now.getSeconds();
		var Time = '[' + min + '分' + Sec + '秒]';

		if(BLEerrorFlag){
			Log(Time + ' - 処理終了 (<red>ESPRacerと未接続</red>)<br><br>');
		}else{
			Log(Time + ' - 処理終了<br><br>');
		}

		CommandAction = false;
		CommandFinish();
	}

	//ログ
	function Log(value) {
		ConsoleLog += "<p class='Consolevalue'>" + value + '</p>';
		Console.innerHTML = ConsoleLog;
		Console.scrollTop = Console.scrollHeight;
	}

	//ランダム関数
	function Random(min, max) {
		var random = Math.floor(Math.random() * (max + 1 - min)) + min;

		return random;
	}

	//Motor関数
	function Motor(Power) {
		var ErrorFlag = false;
		var ErrorValue = '';
		if (typeof Power != 'number') {
			ErrorValue = '[' + typeof Power + ']';
			ErrorFlag = true;
		} else {
			if (Math.abs(Power) > 100) {
				ErrorValue = Power;
				ErrorFlag = true;
			}
		}

		if (ErrorFlag) {
			ErrorOccurd();
			Log('<red>実行エラー</red><br>　Motor関数には-100~100の整数を渡してください<br>現在 : Motor(<red>' + ErrorValue + '</red>);');
		} else {
			PWM(Math.floor(Power) + 100);
		}
	}

	//Servo関数
	function Servo(Power) {
		var ErrorFlag = false;
		var ErrorValue = '';
		if (typeof Power != 'number') {
			ErrorValue = '[' + typeof Power + ']';
			ErrorFlag = true;
		} else {
			if (Math.abs(Power) > 100) {
				ErrorValue = Power;
				ErrorFlag = true;
			}
		}

		if (ErrorFlag) {
			ErrorOccurd();
			Log('<red>実行エラー</red><br>　Servo関数には-100~100の整数を渡してください</red><br>現在 : Servo(<red>' + ErrorValue + '</red>);');
		} else {
			ServoControll(Math.floor(Power) + 100);
		}
	}

	//Port関数
	function Port(port, number) {
		var ErrorFlag1 = false;
		var ErrorFlag2 = false;
		var ErrorValue1 = '';
		var ErrorValue2 = '';
		if (typeof port != 'number') {
			ErrorValue1 = '[' + typeof port + ']';
			ErrorFlag1 = true;
		} else {
			ErrorValue1 = port;
			if (port == 0 || port == 1 || port == 2) {} else {
				ErrorFlag1 = true;
			}
		}
		if (typeof number != 'number') {
			ErrorValue2 = '[' + typeof number + ']';
			ErrorFlag2 = true;
		} else {
			ErrorValue2 = number;
			if (number == 0 || number == 1) {} else {
				ErrorFlag2 = true;
			}
		}

		if (ErrorFlag1 && ErrorFlag2) {
			ErrorOccurd();
			Log('<red>実行エラー</red><br>　Port関数の第1引数には0~2の整数を、第2引数には0か1の整数を渡してください</red><br>現在 : Port(<red>' + ErrorValue1 + '</red>,<red>' + ErrorValue2 + '</red>);');
		} else if (ErrorFlag1) {
			ErrorOccurd();
			Log('<red>実行エラー</red><br>　Port関数の第1引数は0~2の整数を渡してください</red><br>現在 : Port(<red>' + ErrorValue1 + '</red>,' + ErrorValue2 + ');');

		} else if (ErrorFlag2) {
			ErrorOccurd();
			Log('<red>実行エラー</red><br>　Port関数の第2引数は0か1の整数を渡してください</red><br>現在 : Port(' + ErrorValue1 + ',<red>' + ErrorValue2 + '</red>);');
		} else {
			if (port == 0) {
				if (number == 0) {
					PortValue = 0;
				} else if (number == 1) {
					PortValue = 3;
				}
			} else if (port == 1) {
				if (number == 0) {
					//左消灯
					if (PortValue == 3) {
						PortValue = 2;
					} else if (PortValue == 1) {
						PortValue = 0;
					}
				} else if (number == 1) {
					//左点灯
					if (PortValue == 0) {
						PortValue = 1;
					} else if (PortValue == 2) {
						PortValue = 3;
					}
				}
			} else if (port == 2) {
				if (number == 0) {
					//右消灯
					if (PortValue == 3) {
						PortValue = 1;
					} else if (PortValue == 2) {
						PortValue = 0;
					}
				} else if (number == 1) {
					//左点灯
					if (PortValue == 0) {
						PortValue = 2;
					} else if (PortValue == 1) {
						PortValue = 3;
					}
				}
			}
		}
	}

	// ローカルサーバ参照
	//保存先
	const CameraServerURL = 'http://localhost:8080';
	var HttpServerValueColor = [];
	var HttpServerValueX = [];
	var HttpServerValueY = [];
	var HttpServerColorList = ["red", "yellow", "green", "blue"];

	function RequestLocalServer() {
		fetch(CameraServerURL)
			.then(function(response) {
				return response.json();
			})
			.then(function(myJson) {
				let data = JSON.stringify(myJson);
				let value = JSON.parse(data);
				HttpServerValueColor = value.color_list;
				HttpServerValueX = value.x_axis;
				HttpServerValueY = value.y_axis;
			})
			.catch(function(error) {
				Log('<red>参照エラー</red>');
			});
	}

	var ReadLocalServer = {
		red: {
			x: function() {
				return ReturnLocalServerValue('red', 'x');
			},
			y: function() {
				return ReturnLocalServerValue('red', 'y');
			}
		},
		yellow: {
			x: function() {
				return ReturnLocalServerValue('yellow', 'x');
			},
			y: function() {
				return ReturnLocalServerValue('yellow', 'y');
			}
		},
		green: {
			x: function() {
				return ReturnLocalServerValue('green', 'x');
			},
			y: function() {
				return ReturnLocalServerValue('green', 'y');
			}
		},
		blue: {
			x: function() {
				return ReturnLocalServerValue('blue', 'x');
			},
			y: function() {
				return ReturnLocalServerValue('blue', 'y');
			}
		}
	}

	//呼び出し不可関数
	function ReturnLocalServerValue(color, axis) {
		RequestLocalServer();
		if (axis == 'x' || axis == 'y') {
			if (HttpServerValueColor.length > 0) {
				var Check1 = HttpServerValueColor.indexOf(color);
				if (Check1 >= 0) {
					if (axis == 'x') {
						return HttpServerValueX[Check1];
					} else if (axis == 'y') {
						return HttpServerValueY[Check1];
					}
				} else {
					return null;
				}
			} else {
				return null;
			}
		} else {
			return null;
			ErrorOccurd();
			Log('<red>実行エラー</red><br>　ReadLocalServer関数の第2引数にはxかyを指定してください<br>現在 : ReadLocalServer(' + color + ',<red>' + axis + '</red>);');
		}
	}

	// ローカルサーバ参照
	function ReadLocalServerOld() {
		var xhr = new XMLHttpRequest();
		let value, x_val;
		xhr.open('GET', CameraServerURL, true);

		xhr.timeout = 2000; // time in milliseconds

		xhr.onload = function() {
			// Request finished. Do processing here.
			value = JSON.parse(xhr.responseText);
			x_val = value.x_value;
			Log(x_val);
		};
		xhr.ontimeout = function(e) {
			// XMLHttpRequest timed out. Do something here.
			Log("Timeout.");
		};
		xhr.send(null);
	}


	//タブキーを押した際の挙動
	Editer.addEventListener('keydown',
		event => {
			if (event.key == 'Tab') {
				event.preventDefault();

				var Select = Editer.selectionStart;
				var Before = Editer.value.substr(0, Select);
				var After = Editer.value.substr(Select, Editer.value.length);
				Editer.value = Before + '	' + After;
				Editer.setSelectionRange(Select + 1, Select + 1);
			}
		});

	//エンターキーを押した際の挙動
	Editer.addEventListener('keydown',
		event => {
			if (event.key == 'Enter') {

				var Select = Editer.selectionStart;
				var Before = Editer.value.substr(0, Select);
				var After = Editer.value.substr(Select, Editer.value.length);

				var flag = false;
				if (After == '') {
					flag = true;
				} else if (After.match(/^\s/g)) {
					flag = true;
				}

				if (flag && Before.match(/{$/g)) {
					event.preventDefault();
					Editer.value = Before + ' \n\n}' + After;
					Editer.setSelectionRange(Select + 2, Select + 2);

					Editer.scrollTop = Editer.scrollTop + 48;
				}
			}
		});

	//境界線の処理
	//タッチ操作
	Border1.ontouchstart = function(e) {
		Border1.style.backgroundColor = '#ffc9cc';
		StartX1 = e.changedTouches[0].pageX - document.body.clientWidth * NowBorder1 / 100;
		StartX2 = e.changedTouches[0].pageX - document.body.clientWidth * NowBorder2 / 100;
		MoveFlag = -1;
		OnMoveBoarder(0);
		MoveFlag = 1;
	}
	Border2.ontouchstart = function(e) {
		Border2.style.backgroundColor = '#ffc9cc';
		StartX1 = e.changedTouches[0].pageX - document.body.clientWidth * NowBorder1 / 100;
		StartX2 = e.changedTouches[0].pageX - document.body.clientWidth * NowBorder2 / 100;
		MoveFlag = -2;
		OnMoveBoarder(0);
		MoveFlag = 2;
	}
	document.ontouchend = function(e) {
		Border1.style.backgroundColor = 'initial';
		Border2.style.backgroundColor = 'initial';
		if (MoveFlag > 0) {
			MoveFlag = 0;
			localStorage.setItem('SaveData2', NowBorder1 + ',' + NowBorder3);
		}
		TouchAdj = 0;
	}
	document.ontouchmove = function(e) {
		OnMoveBoarder(e.changedTouches[0].pageX);
	}

	//マウス操作
	Border1.onmousedown = function(e) {
		MoveFlag = 1;
		StartX1 = e.clientX - document.body.clientWidth * NowBorder1 / 100;
		StartX2 = e.clientX - document.body.clientWidth * NowBorder2 / 100;
	}
	Border2.onmousedown = function(e) {
		MoveFlag = 2;
		StartX1 = e.clientX - document.body.clientWidth * NowBorder1 / 100;
		StartX2 = e.clientX - document.body.clientWidth * NowBorder2 / 100;
	}
	document.onmouseup = function(e) {
		if (MoveFlag > 0) {
			MoveFlag = 0;
			localStorage.setItem('SaveData2', NowBorder1 + ',' + NowBorder3);
		}
	}
	document.onmousemove = function(e) {
		OnMoveBoarder(e.clientX);
	}

	function OnMoveBoarder(X) {
		ConnandWidthRestrintion = CommandButtonGroup.clientWidth / window.innerWidth * 100;
		WidthRestrintion = 5;

		if (MoveFlag == -1) {
			TouchAdj = 0;
			if (NowBorder1 <= 0) {
				TouchAdj = 15;
				NowBorder1 = 15;
				NowBorder2 = 100 - NowBorder1 - NowBorder3;

				Area1.style.width = NowBorder1 + "%";
				Area2.style.width = NowBorder2 + "%";
			}
		} else if (MoveFlag == -2) {
			if (NowBorder3 <= 0) {
				TouchAdj = 15;
				NowBorder3 = 15;
				NowBorder2 = 100 - NowBorder1 - NowBorder3;

				Area2.style.width = NowBorder2 + "%";
				Area3.style.width = NowBorder3 + "%";
			}
		} else if (MoveFlag == 1) {
			NowBorder1 = (X - StartX1) / window.innerWidth * 100 + TouchAdj;
			NowBorder2 = 100 - NowBorder1 - NowBorder3;

			if (NowBorder1 < WidthRestrintion) {
				NowBorder1 = 0;
				NowBorder2 = 100 - NowBorder1 - NowBorder3;
				MoveFlag = 3;
				BeforeX = X;
			}

			if (NowBorder2 < ConnandWidthRestrintion) {
				NowBorder2 = ConnandWidthRestrintion;
				NowBorder1 = 100 - NowBorder2 - NowBorder3;
				MoveFlag = 4;
				BeforeX = X;
			}

			Area1.style.width = NowBorder1 + "%";
			Area2.style.width = NowBorder2 + "%";
		} else if (MoveFlag == 2) {

			NowBorder2 = (X - StartX2) / window.innerWidth * 100  - TouchAdj;
			NowBorder3 = 100 - NowBorder1 - NowBorder2;

			if (NowBorder2 < ConnandWidthRestrintion) {
				NowBorder2 = ConnandWidthRestrintion;
				NowBorder3 = 100 - NowBorder1 - NowBorder2;
				MoveFlag = 5;
				BeforeX = X;
			}

			if (NowBorder3 < WidthRestrintion) {
				NowBorder3 = 0;
				NowBorder2 = 100 - NowBorder1 - NowBorder3;
				MoveFlag = 6;
				BeforeX = X;
			}

			Area2.style.width = NowBorder2 + "%";
			Area3.style.width = NowBorder3 + "%";
		} else if (MoveFlag == 3) {
			if (X > BeforeX + 10) {
				MoveFlag = 1;
			}
		} else if (MoveFlag == 4) {
			if (X < BeforeX + 10) {
				MoveFlag = 1;
			}
		} else if (MoveFlag == 5) {
			if (X > BeforeX + 10) {
				MoveFlag = 2;
			}
		} else if (MoveFlag == 6) {
			if (X < BeforeX + 10) {
				MoveFlag = 2;
			}
		}
		Area1FontSizeSet();
	}

	function Area1FontSizeSet() {

		var ChapterFontSize = 0.06;
		var CodeFontSize = 0.06;
		var GuideFontSize = 0.04;
		var ExampleFontSize = 0.03;

		for (i = 0; i < Chapter.length; i++) {
			Chapter[i].style.fontSize = NowBorder1 * ChapterFontSize + 'vw';
		}
		for (i = 0; i < ReferenceCode.length; i++) {
			ReferenceCode[i].style.fontSize = NowBorder1 * CodeFontSize + 'vw';
		}
		for (i = 0; i < ReferenceGuide.length; i++) {
			ReferenceGuide[i].style.fontSize = NowBorder1 * GuideFontSize + 'vw';
		}
		for (i = 0; i < ReferenceExample.length; i++) {
			ReferenceExample[i].style.fontSize = NowBorder1 * ExampleFontSize + 'vw';
		}

		Area1.style.width = NowBorder1 + "%";
		Area2.style.width = NowBorder2 + "%";
		Area3.style.width = NowBorder3 + "%";

	};
</script>

</html>
